package com.sdweizan.sdk.bytedance.config.impl;

import lombok.NonNull;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

public class BdRedisConfigStorageImpl extends BdDefaultConfigStorageImpl {
  private static final long serialVersionUID = 3301698081751690429L;
  private static final String ACCESS_TOKEN_KEY_TPL = "%s:access_token:%s";
  private static final String OPEN_ACCESS_TOKEN_KEY_TPL = "%s:open_access_token:%s";
  private static final String LOCK_KEY_TPL = "%s:lock:%s";
  private final String keyPrefix;
  private final RedissonClient redissonClient;
  private String lockKey;
  private String accessTokenKey;
  private String openAccessTokenKey;

  public BdRedisConfigStorageImpl(@NonNull RedissonClient redissonClient) {
    this(redissonClient, null);
  }

  public BdRedisConfigStorageImpl(@NonNull RedissonClient redissonClient, String keyPrefix) {
    this.redissonClient = redissonClient;
    this.keyPrefix = keyPrefix;
  }

  /** 每个小程序生成独有的存储key. */
  @Override
  public void setAppId(String appId) {
    super.setAppId(appId);
    lockKey = String.format(LOCK_KEY_TPL, keyPrefix, appId);
    accessTokenKey = String.format(ACCESS_TOKEN_KEY_TPL, keyPrefix, appId);
    openAccessTokenKey = String.format(OPEN_ACCESS_TOKEN_KEY_TPL, keyPrefix, appId);
    accessTokenLock = redissonClient.getLock(lockKey.concat("accessTokenLock"));
    openAccessTokenLock = redissonClient.getLock(lockKey.concat("openAccessTokenLock"));
  }

  @Override
  public String getAccessToken() {
    Object value = redissonClient.getBucket(accessTokenKey).get();
    return value == null ? null : value.toString();
  }

  @Override
  public String getOpenAccessToken() {
    Object value = redissonClient.getBucket(openAccessTokenKey).get();
    return value == null ? null : value.toString();
  }

  @Override
  public boolean isAccessTokenExpired() {
    long expire = redissonClient.getBucket(accessTokenKey).remainTimeToLive();
    return expire < 200 * 1000;
  }

  @Override
  public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
    if (expiresInSeconds <= 0) {
      redissonClient.getBucket(accessTokenKey).set(accessToken);
    } else {
      redissonClient.getBucket(accessTokenKey).set(accessToken, expiresInSeconds, TimeUnit.SECONDS);
    }
  }

  @Override
  public void expireAccessToken() {
    redissonClient.getBucket(accessTokenKey).expire(0, TimeUnit.SECONDS);
  }

  @Override
  public boolean isOpenAccessTokenExpired() {
    long expire = redissonClient.getBucket(openAccessTokenKey).remainTimeToLive();
    return expire < 200 * 1000;
  }

  @Override
  public synchronized void updateOpenAccessToken(String openAccessToken, int expiresInSeconds) {
    if (expiresInSeconds <= 0) {
      redissonClient.getBucket(openAccessTokenKey).set(openAccessToken);
    } else {
      redissonClient
          .getBucket(openAccessTokenKey)
          .set(openAccessToken, expiresInSeconds, TimeUnit.SECONDS);
    }
  }

  @Override
  public void expireOpenAccessToken() {
    redissonClient.getBucket(openAccessTokenKey).expire(0, TimeUnit.SECONDS);
  }
}
